package cn.ycc1.boot3websocket.handler;

import cn.ycc1.boot3websocket.entity.DanmakuMessage;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import org.springframework.web.socket.CloseStatus;
import org.springframework.web.socket.TextMessage;
import org.springframework.web.socket.WebSocketSession;
import org.springframework.web.socket.handler.TextWebSocketHandler;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author ycc
 * @date 2025/11/19
 */
@Component
public class DanmakuWebSocketHandler extends TextWebSocketHandler {

    // 保存所有连接的会话
    private static final Map<String, WebSocketSession> sessions = new ConcurrentHashMap<>();

    // 按视频ID分组保存会话
    private static final Map<String, Set<String>> videoRooms = new ConcurrentHashMap<>();

    /**
     * 连接建立成功时调用
     */
    @Override
    public void afterConnectionEstablished(WebSocketSession session) throws Exception {
        String sessionId = session.getId();
        sessions.put(sessionId, session);

        System.out.println("新的WebSocket连接建立: " + sessionId);

        // 发送欢迎消息
        String welcomeMsg = "{\"type\":\"system\", \"message\":\"连接成功\"}";
        session.sendMessage(new TextMessage(welcomeMsg));
    }

    /**
     * 收到客户端消息时调用
     */
    @Override
    protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
        String payload = message.getPayload();
        System.out.println("收到消息: " + payload);

        try {
            // 解析JSON消息
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode jsonNode = objectMapper.readTree(payload);

            String type = jsonNode.get("type").asText();

            switch (type) {
                case "join":
                    // 加入视频房间
                    handleJoinRoom(session, jsonNode);
                    break;
                case "danmaku":
                    // 处理弹幕消息
                    handleDanmaku(session, jsonNode);
                    break;
                case "leave":
                    // 离开视频房间
                    handleLeaveRoom(session, jsonNode);
                    break;
                default:
                    System.out.println("未知的消息类型: " + type);
            }
        } catch (Exception e) {
            System.err.println("消息处理错误: " + e.getMessage());
            // 发送错误消息给客户端
            String errorMsg = "{\"type\":\"error\", \"message\":\"消息格式错误\"}";
            session.sendMessage(new TextMessage(errorMsg));
        }
    }

    /**
     * 处理加入房间
     */
    private void handleJoinRoom(WebSocketSession session, JsonNode jsonNode) throws Exception {
        String videoId = jsonNode.get("videoId").asText();
        String sessionId = session.getId();

        // 将会话加入到对应的视频房间
        videoRooms.computeIfAbsent(videoId, k -> ConcurrentHashMap.newKeySet())
                .add(sessionId);

        System.out.println("用户 " + sessionId + " 加入视频房间: " + videoId);

        // 通知客户端加入成功
        String successMsg = String.format("{\"type\":\"join_success\", \"videoId\":\"%s\"}", videoId);
        session.sendMessage(new TextMessage(successMsg));
    }

    /**
     * 处理弹幕消息
     */
    private void handleDanmaku(WebSocketSession session, JsonNode jsonNode) throws Exception {
        String videoId = jsonNode.get("videoId").asText();
        String content = jsonNode.get("content").asText();
        String color = jsonNode.get("color").asText("#FFFFFF");
        String position = jsonNode.get("position").asText("fly");

        // 创建弹幕消息对象
        DanmakuMessage danmaku = new DanmakuMessage();
        danmaku.setType("danmaku");
        danmaku.setContent(content);
        danmaku.setColor(color);
        danmaku.setPosition(position);
        danmaku.setVideoId(videoId);
        danmaku.setTimestamp(System.currentTimeMillis());
        danmaku.setSender(session.getId().substring(0, 8)); // 简化的用户标识

        // 广播给同一视频房间的所有用户
        broadcastToRoom(videoId, danmaku);

        System.out.println("弹幕广播: " + content + " -> 房间: " + videoId);
    }

    /**
     * 处理离开房间
     */
    private void handleLeaveRoom(WebSocketSession session, JsonNode jsonNode) throws Exception {
        String videoId = jsonNode.get("videoId").asText();
        String sessionId = session.getId();

        // 从视频房间移除
        Set<String> roomSessions = videoRooms.get(videoId);
        if (roomSessions != null) {
            roomSessions.remove(sessionId);
        }

        System.out.println("用户 " + sessionId + " 离开视频房间: " + videoId);
    }

    /**
     * 向指定视频房间广播消息
     */
    private void broadcastToRoom(String videoId, DanmakuMessage danmaku) throws Exception {
        Set<String> roomSessions = videoRooms.get(videoId);
        if (roomSessions == null || roomSessions.isEmpty()) {
            return;
        }

        ObjectMapper objectMapper = new ObjectMapper();
        String messageJson = objectMapper.writeValueAsString(danmaku);
        TextMessage message = new TextMessage(messageJson);

        // 向房间内的所有会话发送消息
        for (String sessionId : roomSessions) {
            WebSocketSession targetSession = sessions.get(sessionId);
            if (targetSession != null && targetSession.isOpen()) {
                try {
                    targetSession.sendMessage(message);
                } catch (Exception e) {
                    System.err.println("发送消息失败: " + e.getMessage());
                }
            }
        }
    }

    /**
     * 连接关闭时调用
     */
    @Override
    public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
        String sessionId = session.getId();
        sessions.remove(sessionId);

        // 从所有视频房间中移除
        for (Set<String> roomSessions : videoRooms.values()) {
            roomSessions.remove(sessionId);
        }

        System.out.println("WebSocket连接关闭: " + sessionId + ", 原因: " + status);
    }

    /**
     * 处理传输错误
     */
    @Override
    public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception {
        System.err.println("WebSocket传输错误: " + exception.getMessage());
    }
}
